package org.dding.web.console;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.dding.core.annotation.Service;
import org.dding.core.log.ILogger;
import org.dding.core.log.LoggerFactory;
import org.dding.core.manager.IModuleManager;
import org.dding.core.manager.IServiceManager;
import org.dding.core.util.StringUtils;
import org.dding.msc.service.ServiceController;
import org.dding.msc.service.ServiceController.Mode;
import org.dding.msc.service.ServiceController.State;
import org.dding.msc.service.ServiceInfoWarehouse;
import org.dding.msc.service.ServiceInfoWarehouse.ServiceInfo;
import org.dding.msc.service.ServiceName;
import org.dding.mvc.ActionSupport;
import org.dding.mvc.InvocationContext;
import org.dding.mvc.WebContextLoader;
import org.dding.mvc.annotation.ActionMethod;
import org.dding.mvc.util.Pager;

@Service(name = "serviceAction")
public class ServiceAction extends ActionSupport<Object> {

	private ILogger logger = LoggerFactory.getLogger(getClass());
	private static Map<String, Comparator<WebServiceInfo>> mapping = new HashMap<String, Comparator<WebServiceInfo>>();
	private static String[] properties = { "name", "state", "mode", "module",
			"listener" };
	private List<WebServiceInfo> list;
	private List<String> stopIds = new ArrayList<String>();

	IModuleManager moduleManager = WebContextLoader.getContainer();

	static {
		for (String property : properties) {
			String method = "get" + property.substring(0, 1).toUpperCase()
					+ property.substring(1);
			mapping.put(property,
					new InternalComparator<WebServiceInfo>(method));
		}
	}

	@ActionMethod(
			name = "operation",
			successView = "main/servicelist.jsp",
			httpMethod = ActionMethod.HttpMethod.GET)
	public void operation(InvocationContext invocationContext) {

		String id = invocationContext.getParameterValue("id");
		String opeartion = invocationContext.getParameterValue("operation");
		if (!StringUtils.isEmpty(id) && !StringUtils.isEmpty(opeartion)) {
			IServiceManager manager = findSeriviceManager(id);
			if (manager == null)
				return;
			if ("start".equalsIgnoreCase(opeartion)) {
				manager.startService(id);
				stopIds.remove(id);
			} else if ("stop".equalsIgnoreCase(opeartion)) {
				manager.stopService(id);
				stopIds.add(id);
			} else if ("remove".equalsIgnoreCase(opeartion)) {
				manager.removeService(id);
				stopIds.remove(id);
			} else {
				manager.waitService(id);
			}
		}
		fillAllService();
		invocationContext.getPageContext().setAttribute("pager",
				handlePager(list, null));
	}

	@ActionMethod(
			name = "servicelist",
			successView = "main/servicelist.jsp",
			httpMethod = ActionMethod.HttpMethod.GET)
	public void list(InvocationContext invocationContext) {
		fillAllService();
		invocationContext.getPageContext().setAttribute("pager",
				handlePager(list, null));
	}

	@ActionMethod(
			name = "service",
			successView = "main/servicelist.jsp",
			invocationClass = Pager.class)
	public void service(InvocationContext invocationContext) {
		Pager pagerInvocaion = (Pager) invocationContext.getInvocation();

		String keyword = pagerInvocaion.getKeyword();
		String searchBy = pagerInvocaion.getSearchBy();

		if (!StringUtils.isEmpty(keyword) && !StringUtils.isEmpty(searchBy)) {
			query(invocationContext);
		} else {
			if (pagerInvocaion != null) {
				fillAllService();
				Pager pager = handlePager(list, pagerInvocaion);
				String orderBy = pager.getOrderBy();
				if (!StringUtils.isEmpty(orderBy)) {
					Comparator<WebServiceInfo> comparator = mapping
							.get(orderBy);
					if (comparator != null)
						Collections.sort(list, comparator);
				}
				invocationContext.getPageContext().setAttribute("pager", pager);
			}
		}
	}

	private void query(InvocationContext invocationContext) {
		Pager pagerInvocaion = (Pager) invocationContext.getInvocation();
		String keyword = pagerInvocaion.getKeyword();
		String searchBy = pagerInvocaion.getSearchBy();
		list = new ArrayList<WebServiceInfo>();
		if ("moduleName".equalsIgnoreCase(searchBy)) {
			List<String> services = ServiceInfoWarehouse.getInstance()
					.getServiceByModule(keyword);
			if (services != null) {
				for (String service : services) {
					list.add(findListService(service));
				}
			}
		} else if ("serviceName".equalsIgnoreCase(searchBy)) {
			final List<ServiceName> services = findAllServices();
			for (ServiceName serviceName : services) {
				String name = serviceName.getSimpleName();
				if (StringUtils.containsIgnoreCase(name, keyword))
					list.add(findListService(name));
			}
		} else {
			throw new IllegalArgumentException(
					"only support search by module and service name.");
		}
		invocationContext.getPageContext().setAttribute("pager",
				handlePager(list, null));
	}

	private void fillAllService() {
		final List<ServiceName> services = findAllServices();
		list = new ArrayList<WebServiceInfo>();
		for (ServiceName serviceName : services) {
			WebServiceInfo webServiceInfo = findListService(serviceName
					.getSimpleName());
			list.add(webServiceInfo);
		}

		Iterator<String> it = stopIds.iterator();

		while (it.hasNext()) {

			String id = it.next();
			ServiceInfo serviceInfo = ServiceInfoWarehouse.getInstance()
					.get(id);
			if (serviceInfo == null) {
				it.remove();
				continue;
			}
			WebServiceInfo info = new WebServiceInfo();
			info.setMode(Mode.REMOVE.name());

			info.setModule(serviceInfo.moduleName);
			info.setName(id);
			info.setState(State.STOPPING.name());
			EnableState enable = new EnableState();
			enable.start = true;
			enable.stop = false;
			enable.remove = true;
			enable.wait = false;
			info.setEnableState(enable);
			list.add(info);
		}
	}

	private WebServiceInfo findListService(String serviceName) {

		WebServiceInfo webServiceInfo = new WebServiceInfo();
		IServiceManager manager = findSeriviceManager(serviceName);
		ServiceController<?> controller = manager.getService(serviceName);
		webServiceInfo.setName(serviceName);
		webServiceInfo.setMode(controller.getMode().name());
		webServiceInfo.setState(controller.getState().name());
		ServiceInfo serviceInfo = ServiceInfoWarehouse.getInstance().get(
				serviceName);
		webServiceInfo.setModule(serviceInfo.moduleName);
		EnableState enable = new EnableState();
		if (controller.getState() == State.UP) {
			enable.start = false;
			enable.stop = true;
			enable.remove = false;
			enable.wait = true;
		}
		if (controller.getState() == State.WAITING) {
			enable.start = false;
			enable.stop = true;
			enable.remove = false;
			enable.wait = false;
		}
		if (controller.getState() == State.STOPPING) {
			enable.start = true;
			enable.stop = false;
			enable.remove = true;
			enable.wait = false;
		}
		webServiceInfo.setEnableState(enable);
		return webServiceInfo;
	}

	private IServiceManager findSeriviceManager(String serviceName) {
		IServiceManager[] managers = moduleManager.getServices();
		if (managers == null) {
			logger.info("can't find any service");
			return null;
		}
		IServiceManager manager = null;
		for (IServiceManager temp : managers) {
			if (temp.isServiceExist(serviceName)) {
				manager = temp;
				break;
			}
		}

		if (manager == null) {
			logger.warn("can't find service " + serviceName);
			return null;
		}
		return manager;
	}

	private List<ServiceName> findAllServices() {

		List<ServiceName> list = new ArrayList<ServiceName>();
		IServiceManager[] managers = moduleManager.getServices();
		if (managers == null) {
			logger.info("can't find any service");
			return list;
		}
		for (IServiceManager temp : managers) {
			list.addAll(temp.getServiceNames());
		}
		return list;
	}
}
